import {
  DeepPartial,
  FindManyOptions,
  FindOneOptions,
  Repository,
} from 'typeorm';
import { Logger, NotFoundException } from '@nestjs/common';
import { AbstractEntity } from './abstract.schema';

export abstract class AbstractRepository<T extends AbstractEntity> {
  protected abstract readonly logger: Logger;

  constructor(protected readonly repository: Repository<T>) {}

  async createEntity(entity: DeepPartial<T>): Promise<T> {
    const createdEntity = this.repository.create(entity);
    return await this.repository.save(createdEntity);
  }

  async findOneOrFail(options: FindOneOptions<T>): Promise<T> {
    const entity = await this.repository.findOne(options);
    if (!entity) {
      this.logger.warn('Entity not found with options', options);
      throw new NotFoundException('Entity not found');
    }
    return entity;
  }

  async findOneAndUpdate(
    options: FindOneOptions<T>,
    updateData: DeepPartial<T>,
  ): Promise<T> {
    const entity = await this.findOneOrFail(options);
    const updatedEntity = this.repository.merge(entity, updateData);
    return await this.repository.save(updatedEntity);
  }

  async findEntities(options: FindManyOptions<T>): Promise<T[]> {
    return this.repository.find(options);
  }

  async findOneAndDelete(options: FindOneOptions<T>): Promise<void> {
    const entity = await this.findOneOrFail(options);
    await this.repository.remove(entity);
  }
}
